package org.linlinjava.litemall.wx.util;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.linlinjava.litemall.core.notify.NoticeHelper;
import org.linlinjava.litemall.core.util.AdminCouponDateUtil;
import org.linlinjava.litemall.db.beans.Constants;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.wx.constant.LitemallWXConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static org.linlinjava.litemall.db.beans.Constants.INTEGRAL_LOG_TYPE_ADD;

/**
 * 奖励跑龙套
 *
 * @author yliyun
 * @date 2022/09/27
 */
@Service
public class RewardsUtils {


    /**
     * 用户服务
     */
    @Autowired
    private LitemallUserService userService;

    /**
     * litemall奖励规则服务
     */
    @Autowired
    private LitemallRewardRuleService litemallRewardRuleService;

    /**
     * 奖励服务
     */
    @Autowired
    private RewardsService rewardsService;


    /**
     * litemall奖励规则配置服务
     */
    @Autowired
    private LitemallRewardRuleConfigService litemallRewardRuleConfigService;

    @Autowired
    private LitemallRewardLogService litemallRewardLogService;

    /**
     * litemall分配日志服务
     */
    @Autowired
    private LitemallDistributionLogService litemallDistributionLogService;

    /**
     * litemall分布细节服务
     */
    @Autowired
    private LitemallDistributionDetailService litemallDistributionDetailService;


    @Autowired
    private LumiereCouponStrategyService lumiereCouponStrategyService;

    @Autowired
    private LumiereCouponUserService lumiereCouponUserService;

    /**
     * 完整日志服务
     */
    @Autowired
    private LitemallIntegralLogService integralLogService;

    /**
     * 系统消息通知
     */
    @Autowired
    private NoticeHelper noticeHelper;

    /**
     * 消费赠送奖励
     *
     * @param userId 用户id
     */
    @Transactional(rollbackFor = Exception.class)
    public LitemallIntegralLog getRewardInConsum(Integer userId) {
        //1.查看是否是用户第一次消费
        //List<LitemallRechargeConsumption> count = litemallRechargeConsumptionService.queryByUserIdAndType(userId, (byte) 2);

        List<LitemallIntegralLog> ls = integralLogService.querySelectiveList(userId,INTEGRAL_LOG_TYPE_ADD,null,null,null,null);

        //注册者
        LitemallUser registerUser = userService.findById(userId);

        //邀请者
        List<LitemallUser> invitedUsers = userService.queryUserByInvitedCode(registerUser.getBeenInvitedCode());
        LitemallUser invitedUser = new LitemallUser();
        if (invitedUsers != null && invitedUsers.size() > 0) {
            invitedUser = invitedUsers.get(0);
        }

        if ((ls == null  || ls.size() == 0)  && invitedUser != null) {
            //2.如果是的话就判断该用户的邀请人,查看邀请人一共邀请了多少人并且已经消费过
            List<Integer> ids = rewardsService.countInvitedByUserId(userId);

            List<Integer> noConsum = rewardsService.selectUserIdNoComsu();

            ids = getIntersection(ids, noConsum);

            //3.查看触发哪些规则
            //查询邀请码对应用户的今日邀请记录
            Byte[] giveMethods = {3};
            List<Byte> methods = Arrays.asList(giveMethods);

            List<LitemallRewardRule> list = litemallRewardRuleService.list(null, (byte) 2, methods,true);

            //应该插入或者更新注册者的数据还是邀请者的数据
            boolean registerFlag = false;
            boolean inviteFlag = false;
            Integer ruleId = 0;

            //遍历rule表，查看已上架的rule
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i).getBeneficiary() == 1) {   //邀请人获益
                    inviteFlag = true;
                    ruleId=list.get(i).getId();
                }

                if (list.get(i).getBeneficiary() == 2) {   //受邀请人获益
                    registerFlag = true;
                    ruleId=list.get(i).getId();
                }
            }

            LitemallDistributionLog registeLog = null;                   //注册者的统计数据
            LitemallDistributionLog inviteLog = null;
            if (registerFlag) {
                LitemallDistributionLogExample example = new LitemallDistributionLogExample();
                example.or().andDeletedEqualTo(false).andInviteDateEqualTo(LocalDate.now()).andTypeEqualTo((byte)3).andUserIdEqualTo(userId);
                List<LitemallDistributionLog> logs = litemallDistributionLogService.list(example);

                //注册者当天的记录
                if (logs.size() == 0) {
                    registeLog = new LitemallDistributionLog();
                    registeLog.setUserId(userId);
                    registeLog.setInviteDate(LocalDate.now());
                    registeLog.setInviteNum(1);
                    registeLog.setAddTime(LocalDateTime.now());
                    registeLog.setUpdateTime(LocalDateTime.now());
                    registeLog.setType((byte)3);
                    registeLog.setRuleId(ruleId);
                    registeLog.setDeleted(false);
                    litemallDistributionLogService.add(registeLog);
                }

                LitemallDistributionLog finalLog = registeLog;

                Set<Long> givenCouponIds = new HashSet<>();
                BigDecimal givenPresentPoint = BigDecimal.ZERO;

                for (int i = 0; i < list.size(); i++) {

                    if (list.get(i).getBeneficiary() == 2) {
                        //匹配规则下是否匹配到数量
                        List<LitemallRewardRuleConfig> configs = litemallRewardRuleConfigService.listByRuleIdAndNum(list.get(i).getId(), finalLog.getInviteNum());

                        if (configs.size() != 0) {
                            if (configs.get(0).getPresentCouponId() != null && configs.get(0).getPresentCouponId().length > 0) {
                                givenCouponIds.addAll(Arrays.asList(configs.get(0).getPresentCouponId().clone()));
                            }
                            if (configs.get(0).getPresentPoints() != null && configs.get(0).getPresentPoints().compareTo(BigDecimal.ZERO) != 0) {
                                givenPresentPoint = givenPresentPoint.add(configs.get(0).getPresentPoints());
                            }
                        }
                    }
                }

                return createDistributionDetail(givenCouponIds, givenPresentPoint, finalLog, invitedUser, registerUser,registerUser.getUsername());
            }

            if (inviteFlag) {     //邀请者的统计数据
                LitemallDistributionLogExample example = new LitemallDistributionLogExample();
                example.or().andDeletedEqualTo(false).andInviteDateEqualTo(LocalDate.now()).andTypeEqualTo((byte)3).andUserIdEqualTo(invitedUser.getId());
                List<LitemallDistributionLog> logs = litemallDistributionLogService.list(example);

                if (logs.size() == 0) {
                    inviteLog = new LitemallDistributionLog();
                    inviteLog.setUserId(invitedUser.getId());
                    inviteLog.setInviteDate(LocalDate.now());
                    inviteLog.setInviteNum(1);
                    inviteLog.setAddTime(LocalDateTime.now());
                    inviteLog.setUpdateTime(LocalDateTime.now());
                    inviteLog.setType((byte)3);
                    inviteLog.setRuleId(ruleId);
                    inviteLog.setDeleted(false);
                    litemallDistributionLogService.add(inviteLog);
                } else {
                    inviteLog = logs.get(0);
                    inviteLog.setRuleId(ruleId);
                    inviteLog.setInviteNum(inviteLog.getInviteNum() + 1);
                    inviteLog.setUpdateTime(LocalDateTime.now());
                    litemallDistributionLogService.update(inviteLog);
                }

                LitemallDistributionLog finalLog = inviteLog;

                Set<Long> givenCouponIds = new HashSet<>();
                BigDecimal givenPresentPoint = BigDecimal.ZERO;

                for (int i = 0; i < list.size(); i++) {

                    if (list.get(i).getBeneficiary() == 1) {
                        List<LitemallRewardRuleConfig> configs = litemallRewardRuleConfigService.listByRuleIdAndNum(list.get(i).getId(), finalLog.getInviteNum());

                        if (configs.size() != 0) {
                            if (configs.get(0).getPresentCouponId() != null && configs.get(0).getPresentCouponId().length > 0) {
                                givenCouponIds.addAll(Arrays.asList(configs.get(0).getPresentCouponId().clone()));
                            }

                            if (configs.get(0).getPresentPoints() != null && configs.get(0).getPresentPoints().compareTo(BigDecimal.ZERO) != 0) {
                                givenPresentPoint = givenPresentPoint.add(configs.get(0).getPresentPoints());
                            }
                        }
                    }
                }
                return createDistributionDetail(givenCouponIds, givenPresentPoint, finalLog, invitedUser, registerUser,registerUser.getUsername());
            }
        }
        return null;
    }

    /**
     * 邀请就赠送奖励
     *
     * @param user 用户
     */
    @Transactional(rollbackFor = Exception.class)
    @Async
    public void getRewardInvitation(LitemallUser user,String inviteUser) {
        if (ObjectUtil.isNull(user)) {return ;}
        //获得奖励规则
        List<LitemallRewardRule> rewardRules = litemallRewardRuleService.list(Wrappers.lambdaQuery(LitemallRewardRule.class)
                .eq(LitemallRewardRule::getStatus,2)
                .eq(LitemallRewardRule::getGiveMethod,1)
                .lt(LitemallRewardRule::getStartDate,LocalDateTime.now())
                .gt(LitemallRewardRule::getEndDate,LocalDateTime.now())
        );
        rewardRules.stream().forEach(rewardRule->{
            //获取配置
            List<LitemallRewardRuleConfig> litemallRewardRuleConfigs = litemallRewardRuleConfigService.listByRuleId(rewardRule.getId());
            //获得要邀请人的推广次数
            Integer promoteNum = litemallRewardLogService.getPromoteNum(user.getId());
            //查看收益方
            if(rewardRule.getBeneficiary()==1){
                for (LitemallRewardRuleConfig rewardRuleConfig : litemallRewardRuleConfigs) {
                    //查看是否达到推广次数
                    if(promoteNum> rewardRuleConfig.getPerNum()) continue;

                    //发放奖励
                    //用户获得优惠券
                    for (int i = 0; i < rewardRuleConfig.getPresentCouponId().length; i++) {
                        LumiereCouponStrategy lumiereCouponStrategy = lumiereCouponStrategyService.findByid(rewardRuleConfig.getPresentCouponId()[i]);
                        long nextId = IdUtil.getSnowflake(2, 2).nextId();
                        LocalDateTime[] localDateTimes = AdminCouponDateUtil.calculateExpirationTime(lumiereCouponStrategy);
                        //发放券
                        LumiereCouponUser couponUser = LumiereCouponUser.builder()
                                .userId(user.getId())
                                .strategyId(lumiereCouponStrategy.getId())
                                .couponId(lumiereCouponStrategy.getCouponId())
                                .userName(user.getUsername())
                                .startTime(localDateTimes[0])
                                .endTime(localDateTimes[1])
                                .code(String.valueOf(nextId))
                                .addTime(LocalDateTime.now())
                                .updateTime(LocalDateTime.now())
                                .deleted(false)
                                .build();
                        lumiereCouponUserService.save(couponUser);
                        //发送获得优惠券的系统通知
                        noticeHelper.noticeUser(Constants.MSG_TYPE_OTHER,LitemallWXConstants.WX_INVITATION_USER_TITLE_NOTICEMAIL,LitemallWXConstants.WX_INVITATION_USER_COUPON_NOTICEMAIL,user.getId(),couponUser);
                    }
                    //注册用户获取积分
                    user.setInviteNum(user.getInviteNum() == null ? 0 : user.getInviteNum() + 1);
                    user.setPoints(user.getPoints().add(rewardRuleConfig.getPresentPoints()==null?BigDecimal.ZERO:rewardRuleConfig.getPresentPoints()));
                    userService.updateById(user);
                    LitemallIntegralLog l = new LitemallIntegralLog();
                    l.setUserId(user.getId());
                    l.setType(INTEGRAL_LOG_TYPE_ADD);
                    l.setPoints(user.getPoints());
                    l.setChangePoints(rewardRuleConfig.getPresentPoints()==null?BigDecimal.ZERO:rewardRuleConfig.getPresentPoints());
                    integralLogService.add(l);
                    //发送获得积分的系统通知
                    noticeHelper.noticeUser(Constants.MSG_TYPE_OTHER,LitemallWXConstants.WX_INVITATION_USER_TITLE_NOTICEMAIL,String.format(LitemallWXConstants.WX_INVITATION_USER_POINTS_NOTICEMAIL,l.getChangePoints()),user.getId(),l);
                    //推广记录
                    LitemallRewardLog rewardLog = LitemallRewardLog.builder()
                            .ruleId(rewardRuleConfig.getRewardRuleId())
                            .userId(user.getId())
                            .registerUsername(inviteUser)
                            .presentCouponId(rewardRuleConfig.getPresentCouponId())
                            .presentPoints(rewardRuleConfig.getPresentPoints())
                            .giveMethod(rewardRule.getGiveMethod().intValue())
                            .beneficiary(rewardRule.getBeneficiary().intValue())
                            .addTime(LocalDateTime.now())
                            .updateTime(LocalDateTime.now())
                            .deleted(false)
                            .build();
                    litemallRewardLogService.save(rewardLog);
                }
            }
        });


        //查看邀请前的实际邀请数量
        /*Integer inviteNum  = user.getInviteNum() == null ? 0 : user.getInviteNum();

        Byte[] giveMethods = {1};
        List<Byte> methods = Arrays.asList(giveMethods);

        List<LitemallRewardRule> list = litemallRewardRuleService.list(null, (byte) 2, methods,true);

        //应该插入或者更新注册者的数据还是邀请者的数据
        boolean inviteFlag = false;

        //当前判断的规则id
        Integer ruleId = 0;

        //遍历rule表，查看已上架的rule
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).getBeneficiary() == 1) {   //邀请人获益
                inviteFlag = true;
                ruleId=list.get(i).getId();
            }
        }
        LitemallDistributionLog inviteLog = null;


        if (inviteFlag) {     //邀请者的统计数据
            LitemallDistributionLogExample example = new LitemallDistributionLogExample();
            example.or().andDeletedEqualTo(false).andTypeEqualTo((byte) 1).andInviteDateEqualTo(LocalDate.now()).andUserIdEqualTo(user.getId());
            List<LitemallDistributionLog> logs = litemallDistributionLogService.list(example);

            if (logs.size() == 0) {
                inviteLog = new LitemallDistributionLog();
                inviteLog.setUserId(user.getId());
                inviteLog.setInviteDate(LocalDate.now());
                inviteLog.setInviteNum(1);
                inviteLog.setAddTime(LocalDateTime.now());
                inviteLog.setUpdateTime(LocalDateTime.now());
                inviteLog.setType((byte) 1);
                inviteLog.setRuleId(ruleId);
                inviteLog.setDeleted(false);
                litemallDistributionLogService.add(inviteLog);
            } else {
                inviteLog = logs.get(0);
                inviteLog.setRuleId(ruleId);
                inviteLog.setInviteNum(logs.get(0).getInviteNum() + 1);
                inviteLog.setUpdateTime(LocalDateTime.now());
                litemallDistributionLogService.update(inviteLog);
            }

            LitemallDistributionLog finalLog = inviteLog;

            Set<Long> givenCouponIds = new HashSet<>();
            BigDecimal givenPresentPoint = BigDecimal.ZERO;

            for (int i = 0; i < list.size(); i++) {

                if (list.get(i).getBeneficiary() == 1) {
                    List<LitemallRewardRuleConfig> configs = litemallRewardRuleConfigService.listByRuleIdAndNum(list.get(i).getId(), inviteLog.getInviteNum());

                    if (configs.size() != 0) {
                        if (configs.get(0).getPresentCouponId() != null && configs.get(0).getPresentCouponId().length > 0) {
                            givenCouponIds.addAll(Arrays.asList(configs.get(0).getPresentCouponId().clone()));
                        }

                        if (configs.get(0).getPresentPoints() != null && configs.get(0).getPresentPoints().compareTo(BigDecimal.ZERO) != 0) {
                            givenPresentPoint = givenPresentPoint.add(configs.get(0).getPresentPoints());
                        }
                    }
                }
            }
             createDistributionDetail(givenCouponIds, givenPresentPoint, finalLog, user, null,inviteUser);
        }*/
    }


    /**
     * 得到十字路口
     *
     * @param list1 list1
     * @param list2 用于
     * @return {@link List}<{@link Integer}>
     */
    public List<Integer> getIntersection(List<Integer> list1,
                                         List<Integer> list2) {
        List<Integer> result = new ArrayList<>();
        for (Integer integer : list2) {//遍历list1
            if (list1.contains(integer)) {//如果存在这个数
                result.add(integer);//放进一个list里面，这个list就是交集
            }
        }
        return result;
    }

    /**
     * 创建分布细节
     *
     * @param givenCouponIds    鉴于优惠券id
     * @param givenPresentPoint 鉴于目前点
     * @param finalLog          最后日志
     * @param user              用户
     * @param registerUser      注册用户
     */
    public LitemallIntegralLog createDistributionDetail(Set<Long> givenCouponIds, BigDecimal givenPresentPoint,
                                         LitemallDistributionLog finalLog, LitemallUser user,LitemallUser registerUser,String registerUsername) {
        //
        if (givenCouponIds.size() > 0 || givenPresentPoint.compareTo(BigDecimal.ZERO) > 0) {
            LitemallDistributionDetail detail = new LitemallDistributionDetail();
            detail.setDisLogId(finalLog.getId());
            detail.setRegisterId(ObjectUtil.isNotNull(registerUser)?registerUser.getId():0);
            detail.setRegisterUsername(registerUsername);
            detail.setPresentCouponId(givenCouponIds.toArray(new Long[givenCouponIds.size()]));
            detail.setAddTime(LocalDateTime.now());
            detail.setUpdateTime(LocalDateTime.now());
            detail.setPresentPoints(givenPresentPoint);
            detail.setDeleted(false);

            litemallDistributionDetailService.add(detail);

            //用户获得优惠券
            for (int i = 0; i < detail.getPresentCouponId().length; i++) {
                LumiereCouponStrategy lumiereCouponStrategy = lumiereCouponStrategyService.findByid(detail.getPresentCouponId()[i]);
                long nextId = IdUtil.getSnowflake(2, 2).nextId();
                LocalDateTime[] localDateTimes = AdminCouponDateUtil.calculateExpirationTime(lumiereCouponStrategy);
                //发放券
                LumiereCouponUser couponUser = LumiereCouponUser.builder()
                        .userId(user.getId())
                        .strategyId(lumiereCouponStrategy.getId())
                        .couponId(lumiereCouponStrategy.getCouponId())
                        .userName(user.getUsername())
                        .startTime(localDateTimes[0])
                        .endTime(localDateTimes[1])
                        .code(String.valueOf(nextId))
                        .addTime(LocalDateTime.now())
                        .updateTime(LocalDateTime.now())
                        .deleted(false)
                        .build();
                lumiereCouponUserService.save(couponUser);
                //发送获得优惠券的系统通知
                noticeHelper.noticeUser(Constants.MSG_TYPE_OTHER,LitemallWXConstants.WX_INVITATION_USER_TITLE_NOTICEMAIL,LitemallWXConstants.WX_INVITATION_USER_COUPON_NOTICEMAIL,user.getId(),couponUser);

            }

            //注册用户获取积分
            user.setInviteNum(user.getInviteNum() == null ? 0 : user.getInviteNum() + 1);
            user.setPoints(user.getPoints().add(givenPresentPoint));
            userService.updateById(user);
            LitemallIntegralLog l = new LitemallIntegralLog();
            l.setUserId(user.getId());
            l.setType(INTEGRAL_LOG_TYPE_ADD);
            l.setPoints(user.getPoints());
            l.setChangePoints(givenPresentPoint);
            integralLogService.add(l);
            //发送获得积分的系统通知
            noticeHelper.noticeUser(Constants.MSG_TYPE_OTHER,LitemallWXConstants.WX_INVITATION_USER_TITLE_NOTICEMAIL,String.format(LitemallWXConstants.WX_INVITATION_USER_POINTS_NOTICEMAIL,l.getChangePoints()),user.getId(),l);
            return l;
        }
        return null;
    }


}
